﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Xml;

namespace OK.SCOM.Authoring.Tools.MPElementsExtract
{
	internal class MPElementTypeDWScript: MPElementTypeBase
	{

		private string m_name;
		private string m_contentInstall;
		private XmlNode m_nodeInstall;
		private string m_contentUpgrade;
		private XmlNode m_nodeUpgrade;
		private string m_contentUninstall;
		private XmlNode m_nodeUninstall;

		private Dictionary<string, string> m_ScriptDictionary;

		internal enum ExtractionMode { ScriptsExtract, SubScriptsExtract }

		internal ExtractionMode Mode { get; set; }

		internal override string Name
		{
			get
			{
				return String.Format("Data Warehouse Scripts ({0})", Mode);
			}
		}

		internal override bool SupportsEmbed
		{
			get { return (Mode == ExtractionMode.SubScriptsExtract) ? true : false; }
		}

		internal override bool SupportsExtractReplaceWithPlaceMarks
		{
			get
			{
				return (Mode == ExtractionMode.SubScriptsExtract) ? true : false;
			}
		}

		internal MPElementTypeDWScript(string baseDirectory, string extractBaseDirectory)
			: base(baseDirectory, extractBaseDirectory)
		{
			m_name = "";
			m_contentInstall = "";
			m_contentUninstall = "";
			m_contentUpgrade = "";

			m_nodeInstall = null;
			m_nodeUninstall = null;
			m_nodeUpgrade = null;

			m_ScriptDictionary = new Dictionary<string, string>();

			Mode = ExtractionMode.ScriptsExtract;
		}

		protected override void ProcessSingleNodeBeforeChildren(System.Xml.XmlNode node, ParseAction action)
		{
			if (node.Name == "DataWarehouseScript" && node.ParentNode.Name == "DataWarehouseScripts")
			{
				m_name = node.Attributes["ID"].Value;
				
				m_contentInstall = "";
				m_contentUninstall = "";
				m_contentUpgrade = "";

				m_nodeInstall = null;
				m_nodeUninstall = null;
				m_nodeUpgrade = null;
			}
		}

		protected override void ProcessSingleNodeAfterChild(System.Xml.XmlNode node, ParseAction action)
		{
			//
		}

		protected override void ProcessSingleNodeAfterChildren(System.Xml.XmlNode node, ParseAction action)
		{
			if (node.Name == "Install" && node.ParentNode.Name == "DataWarehouseScript")
			{
				m_contentInstall = node.InnerText;
				m_nodeInstall = node;
			}
			else if (node.Name == "Uninstall" && node.ParentNode.Name == "DataWarehouseScript")
			{
				m_contentUninstall = node.InnerText;
				m_nodeUninstall = node;
			}
			else if (node.Name == "Upgrade" && node.ParentNode.Name == "DataWarehouseScript")
			{
				m_contentUpgrade = node.InnerText;
				m_nodeUpgrade = node;
			}
			else if (node.Name == "DataWarehouseScript" && node.ParentNode.Name == "DataWarehouseScripts")
			{
				if (action == ParseAction.ExtractNoPlaceMarks || action == ParseAction.ExtractReplaceWithPlaceMarks)
				{
					if (m_contentInstall.Length > 0 && m_nodeInstall!=null) Extract(action, string.Format("{0}_install", m_name), m_nodeInstall);
					if (m_contentUninstall.Length > 0 && m_nodeUninstall!=null) Extract(action, string.Format("{0}_uninstall", m_name), m_nodeUninstall);
					if (m_contentUpgrade.Length > 0 && m_nodeUpgrade!=null) Extract(action, string.Format("{0}_upgrade", m_name), m_nodeUpgrade);
				}
				if (action == ParseAction.Embed)
				{
					if (m_contentInstall.Length > 0 && m_nodeInstall != null) EmbedContent(m_nodeInstall);
					if (m_contentUninstall.Length > 0 && m_nodeUninstall != null) EmbedContent(m_nodeUninstall);
					if (m_contentUpgrade.Length > 0 && m_nodeUpgrade != null) EmbedContent(m_nodeUpgrade);
				}
			}
		}

		private void Extract(ParseAction action, string name, XmlNode contentNode)
		{
			string content = contentNode.InnerText;

			if (Mode == ExtractionMode.ScriptsExtract)
			{
				int scriptNo = 0;

				while (m_ScriptDictionary.ContainsKey(GenerateScriptName(name, scriptNo)) &&
					m_ScriptDictionary[GenerateScriptName(name, scriptNo)] != content) ++scriptNo;

				string scriptName = GenerateScriptName(name, scriptNo);

				Save(content, scriptName + ".sql");

				Console.WriteLine("DW Script found: {0} ({1} bytes), saved as: {2}", name, content.Length, scriptName);

			}
			if (Mode == ExtractionMode.SubScriptsExtract)
			{
				string[] lines = content.Split(new String[] { "\r\n" }, StringSplitOptions.None);
				string subScriptBody = "";
				string scriptBodyNew = "";
				string subScriptName = name;

				foreach (string line in lines)
				{
					if (line.Contains("#####"))
					{
						if (subScriptName.Length > 0 && subScriptBody.Length > 0)
						{
							string scriptNameNew = SaveSubScript(subScriptName, subScriptBody);
							if (scriptBodyNew.Length > 0) scriptBodyNew += "\r\n";
							scriptBodyNew += "{{" + scriptNameNew + "}}";
						}

						int idx = line.IndexOf("#####");
						subScriptName = line.Substring(idx + 5);
						subScriptBody = "";
					}

					if (subScriptName != "")
					{
						if (subScriptBody.Length > 0) subScriptBody += "\r\n";
						if(!(subScriptBody.Length==0 && line.Trim()==""))	subScriptBody += line;
					}
				}

				if (subScriptName.Length > 0 && subScriptBody.Length > 0)
				{
					string scriptNameNew = SaveSubScript(subScriptName, subScriptBody);
					if (scriptBodyNew.Length > 0) scriptBodyNew += "\r\n";
					scriptBodyNew += "{{" + scriptNameNew + "}}";
				}

				if (action == ParseAction.ExtractReplaceWithPlaceMarks)
				{
					contentNode.InnerText = scriptBodyNew;
				}
			}
		}

		private string SaveSubScript(string subScriptName, string subScriptBody)
		{
			int scriptNo = 0;

			while (m_ScriptDictionary.ContainsKey(GenerateScriptName(subScriptName, scriptNo)) &&
				m_ScriptDictionary[GenerateScriptName(subScriptName, scriptNo)] != subScriptBody) ++scriptNo;

			subScriptName = GenerateScriptName(subScriptName, scriptNo);

			if (!subScriptName.EndsWith(".sql")) subScriptName += ".sql";

			string scriptNameNew = Save(subScriptBody, subScriptName);

			Console.WriteLine("DW Script found: {0} ({1} bytes), saved as: {2}", subScriptName, subScriptBody.Length, scriptNameNew);

			return scriptNameNew;
		}

		private string GenerateScriptName(string n, int i)
		{
			string res = n;

			if (i > 0)
			{
				res = ((i < 10) ? "0" : "") + i.ToString() + "_" + res;
			}

			return res;
		}

	}
}
